; hashGen.asm
; This tools generate hashes for all function of main Windows API function
; 

.386
.model flat,stdcall
option casemap:none

include     \masm32\include\windows.inc
include     \masm32\include\masm32.inc
include     \masm32\include\user32.inc
include     \masm32\include\kernel32.inc

includelib  \masm32\lib\masm32.lib
includelib  \masm32\lib\kernel32.lib
includelib  \masm32\lib\user32.lib

.data
    
    Space   db  " ",0
    RC      db  13,10,0
    ModName dd  0
    HashBuf db  1024 dup(0)
    LibWs2  db  "ws2_32",0

.code

;; Program start point
start:
    push offset LibWs2
    call LoadLibraryA
FindFunctions:
    assume fs:NOTHING                           ; unset ERROR
    mov ebp,esp                                 ; Create a new stack frame
    xor edx,edx
    mov edx,fs:[edx+48]                         ; edx = pointer to the PEB
    mov edx,[edx+12]                            ; edx = PEB->Ldr
    mov edx,[edx+20]                            ; edx = first module of the module list
    
_nextMod:
    mov esi,[edx+40]                            ; esi = pointer to modules name
    movzx ecx,WORD ptr [edx+38]                 ; ecx = length of module name
    xor edi,edi
    mov DWORD ptr [ModName],esi
    
_hashmodLoop:
    xor eax,eax
    lodsb                                       ; Read the next byte of the name
    cmp al,'a'                                  ; If current character is uppercase
    jl _rotate                                  ;   jmp to _rotate
    sub al,20h                                  ; Else sub 32 to get uppercase char
    
_rotate:
    ror edi,13                                  ; Rotate right our hash value
    add edi,eax                                 ; Add the next byte of the name
    loop _hashmodLoop                           ; Loop untill we have read enough (while ecx != 0)
    push edx                                    ; Save current position in the module list
    push edi                                    ; Save current module hash

_iterateExporteTable:
    mov edx,[edx+16]                            ; edx = current module base address
    mov eax,[edx+60]                            ; eax = PE header offset
    add eax,edx                                 ; eax = PE header offset + module base address
    mov eax,[eax+120]                           ; eax = Export tables rva
    test eax,eax                                ; If no Export address table
    jz _getNextMod1                             ;   process with next module
    add eax,edx                                 ; eax = Export tables va
    push eax                                    ; Save Export tables address
    mov ecx,[eax+24]                            ; ecx = number of function names
    mov ebx,[eax+32]                            ; ebx = function name rva
    add ebx,edx                                 ; ebx = function name va

_getNextFunc:
    jecxz _getNextMod                           ; If ecx = 0 Then jmp to _get_next_mod
    dec ecx                                     ; Decrement function name counter
    mov esi,[ebx+ecx*4]                         ; esi = next module name rva
    add esi,edx                                 ; esi = next module name va
    pushad
    invoke StdOut,ModName
    invoke StdOut,offset Space
    invoke StdOut,esi
    invoke StdOut,offset Space
    popad
    xor edi,edi
  
_funcnameLoop:
    xor eax,eax
    lodsb                                       ; Read the next byte of function name
    ror edi,13                                  ; Rotate right our hash value
    add edi,eax                                 ; Add the next byte of the name
    cmp al,0h                                   ; If next byte of the name != '\0'
    jne _funcnameLoop                           ;   Continue hashing name
    add edi,[ebp-8]                             ; edi = function hash + current module hash
    pushad
    invoke dw2hex,edi,offset HashBuf
    invoke StdOut,offset HashBuf
    invoke StdOut,offset RC
    popad
    jmp _getNextFunc                            ; Proceed with next function name
  
_getNextMod:
    pop eax                                     ; Pop previous module Export Address Table
  
_getNextMod1:
    pop edi                                     ; Pop previous module hash
    pop edx                                     ; Restore position in the module list
    mov edx,[edx]                               ; Get the next module
    jmp _nextMod                                ; Process with next module
    
end start